package com.xzkydz.sensor.service;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.IBinder;

import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;


import com.xzkydz.serialport.R;
import com.xzkydz.sensor.helper.ComControl;
import com.xzkydz.sensor.original.OriginalBean;
import com.xzkydz.sensor.sensor.ChaYaAckBean;
import com.xzkydz.sensor.sensor.ChaYaBean;
import com.xzkydz.sensor.sensor.JiGuangBean25;
import com.xzkydz.sensor.sensor.JiGuangBean26;
import com.xzkydz.sensor.sensor.YaLiAckBean;
import com.xzkydz.sensor.sensor.YaLiBean;
import com.xzkydz.sensor.sensor.base.BaseSensorData;
import com.xzkydz.sensor.sensor.bean.AskMsgBean;
import com.xzkydz.sensor.utils.CalculationUtils;
import com.xzkydz.sensor.utils.SensorLogger;
import com.xzkydz.serialport.SerialControl;


import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.util.HashMap;
import java.util.Map;

/**
 * 串口解析服务
 */
public class SerialPortService extends Service {

    public final static int OPEN_FILL_LOST_DATAS = 1;
    private String contentTitle = "数据接收";
    private String contentText = "传感器数据接收中...";
    private OnGetSerialPortDataThread onGetSerialPortData;
    private OnAddNewSensorType onAddNewSensorType;
    /**
     * 是否默认解析
     */
    private boolean isDeFault = true;

    //串口实例化
    private SerialControl com;
    private boolean isReadSerial = false;
    private OriginalBean originalBean = new OriginalBean();
    private NotificationManager notificationManager;
    private Map<String, BaseSensorData> sensorDataMap = new HashMap<>();
    private Thread readDataThread = null;

    private static final String CHANNEL_ID = "SerialService";

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onCreate() {
        super.onCreate();
        EventBus.getDefault().register(this);
        com = new SerialControl(true);
        com.setiDelay(5);
        com.setOpenXor(false);
        ComControl.openComPort(this, com);
    }

    /**
     * 发送请求命令
     *
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void getAskEvent(AskMsgBean event) {
        if (event.getSendContent() != null && event.getSendContent().length() != 0) {
            com.sendHex(event.getSendContent());
        }
        SensorLogger.d("收到请求命令: " + event.toString());
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        final String CHANNEL_ID = "串口";
        final String CHANNEL_NAME = "串口解析服务";

        // 注册通知服务
        notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        Notification.Builder builder = new Notification.Builder(this.getApplicationContext());      // 获取一个Notification构造器
        builder.setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.danpianji)) // 设置下拉列表中的图标(大图标)
                .setContentTitle(contentTitle)       // 设置下拉列表里的标题
                .setSmallIcon(R.mipmap.danpianji)    // 设置状态栏内的小图标
                .setContentText(contentText)         // 设置上下文内容
                .setWhen(System.currentTimeMillis()) // 设置该通知发生的时间
                .setVibrate(null)
                .setVibrate(new long[]{0l})
                .setSound(null)
                .setLights(0, 0, 0)
                .setDefaults(NotificationCompat.FLAG_ONLY_ALERT_ONCE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //修改安卓8.1以上系统报错
            NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_MIN);
            notificationChannel.enableLights(false); //如果使用中的设备支持通知灯，则说明此通知通道是否应显示灯
            notificationChannel.setShowBadge(false); //是否显示角标
            notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            manager.createNotificationChannel(notificationChannel);
            builder.setChannelId(CHANNEL_ID);
        }

        Notification notification = builder.build();               // 获取构建好的Notification
        notification.defaults = Notification.FLAG_ONLY_ALERT_ONCE; /*设置为默认的声音*/
        startForeground(110, notification);

        //开启读取线程
        isReadSerial = true;
        if (readDataThread == null || readDataThread.isInterrupted()) {
            if (isDeFault) {
                readDataThread = new ReadDataThread();
            } else {
                readDataThread = new ReadDataThread2();
            }
            readDataThread.start();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 串口解析线程
     */
    public class ReadDataThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (isReadSerial && !isInterrupted()) {
                try {
                    byte[] comData;
                    while (isReadSerial && (comData = com.QueueList.poll()) != null) {
                        // 接收到数据
                        int type = comData[9];
                        //设备编号
                        int devNum = CalculationUtils.oneByteToIntNoSign(comData[10]);
                        SensorLogger.d(CalculationUtils.byteArrToHex(comData) + "  类型 : " + type + "  长度 : " + comData.length);
                        byte[] buffer = comData;
                        String key = getCommonKey(type, devNum, buffer);
                        BaseSensorData baseSensorData = sensorDataMap.get(key);
                        if (baseSensorData == null) {
                            baseSensorData = getBaseSensorData(type, buffer);
                            if (baseSensorData == null) {//没有找到对应传感器
                                if (null != onAddNewSensorType) {
                                    onAddNewSensorType.onGetData(buffer, type);
                                }
                                continue;
                            } else {
                                //新添加传感器需要对应key和bean对象
                                sensorDataMap.put(key, baseSensorData);
                            }
                        }
                        switch (type) {
                            case 32: //0x20  20Mpa 无线压力传感器
                                SensorLogger.d(" 20Mpa压力" + (buffer.length == 22 ? "ACK" : "数据"));
                                baseSensorData.caculateFunc(buffer);
                                break;
                            case 33: //0x21  60MPA
                                SensorLogger.d("run:0x21  60Mpa压力" + (buffer.length == 22 ? "ACK" : "数据"));
                                baseSensorData.caculateFunc(buffer);
                                break;
                            case 35: //0x23  -0.1~ 1 MPa
                                SensorLogger.d("run:0x23  -0.1~ 1 MPa压力" + (buffer.length == 22 ? "ACK" : "数据"));
                                baseSensorData.caculateFunc(buffer);
                                break;
                            case 36: //0x24  -0.1~1.5
                                SensorLogger.d("run:0x24  -0.1~1.5 MPa压力" + (buffer.length == 22 ? "ACK" : "数据"));
                                baseSensorData.caculateFunc(buffer);
                                break;
                            case 37: //0x25   -0.2 ~ 10
                                SensorLogger.d("run:0x25  -0.2 ~ 10 MPa压力" + (buffer.length == 22 ? "ACK" : "数据"));
                                baseSensorData.caculateFunc(buffer);
                                break;
                            case 38: //0x26   -1.5 ~ 0 kPa
                                SensorLogger.d("run:0x26  -1.5 ~ 0 kPa压力" + (buffer.length == 22 ? "ACK" : "数据"));
                                baseSensorData.caculateFunc(buffer);
                                break;
                            case 39: //0x27   0 ~ 2000 hPa  / 10
                                SensorLogger.d("run:0x27  0 ~ 2000 hPa压力" + (buffer.length == 22 ? "ACK" : "数据"));
                                baseSensorData.caculateFunc(buffer);
                                break;
                            case 34: //0x22 -8Kpa差压协议
                                SensorLogger.d("run:0x22 -8Kpa 差压" + (buffer.length == 22 ? "ACK" : "数据"));
                                baseSensorData.caculateFunc(buffer);
                                break;
                            case 48: //-2 ~ 2 kPa 差压
                                SensorLogger.d("run:-2 ~ 2 kPa 差压" + (buffer.length == 22 ? "ACK" : "数据"));
                                baseSensorData.caculateFunc(buffer);
                                break;
                            case -95: // 激光测距
                            case 161: // 激光测距
                                SensorLogger.d("run: 激光测距传感器");
                                baseSensorData.caculateFunc(buffer);
                                break;
                            default:
                                SensorLogger.d("run: 未对应类型");
                                baseSensorData.caculateFunc(buffer);
                                break;
                        }
                        //上面做处理 此处baseSensorData不为null
                        EventBus.getDefault().post(baseSensorData);
                        try {
                            Thread.sleep(10);//显示性能高的话，可以把此数值调小。
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                    }
                } catch (Exception e) {
                    SensorLogger.d("run: 解析串口数据的时候产生异常 --> " + e.getMessage());
                    e.printStackTrace();
                }
            }
        }
    }

    /*解析串口线程*/
    public class ReadDataThread2 extends Thread {
        @Override
        public void run() {
            super.run();
            while (isReadSerial && !isInterrupted()) {
                try {
                    final byte[] comData;
                    while (isReadSerial && (comData = com.QueueList.poll()) != null) {
                        // 接收到数据
                        onGetSerialPortData.onGetData(comData, comData[9]);
                        EventBus.getDefault().post(originalBean.setDataArray(comData));
                        try {
                            Thread.sleep(10);//显示性能高的话，可以把此数值调小。
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                    }
                } catch (Exception e) {
                    SensorLogger.d("run: 解析串口数据的时候产生异常 --> " + e.getMessage());
                }
            }
        }
    }

    /**
     * 解析数据统一key
     * 类型_编号 ： 对应唯一数据
     * @param sensorType      传感器类型
     * @param sensorNumberVel 传感器编号
     * @param buffer
     * @return
     */
    private String getCommonKey(int sensorType, int sensorNumberVel, byte[] buffer) {
        String keyData = sensorType + "_" + sensorNumberVel;
        //处理ack heart等特殊key
        switch (sensorType) {
            case 32: //0x20  20Mpa 无线压力传感器
            case 33: //0x21  60MPA
            case 35: //0x23  -0.1~ 1 MPa
            case 36: //0x24  -0.1~1.5
            case 37: //0x25   -0.2 ~ 10
            case 38: //0x26   -1.5 ~ 0 kPa
            case 39: //0x27   0 ~ 2000 hPa  / 10
            case 34: //0x22 -8Kpa差压协议
            case 48: //-2 ~ 2 kPa 差压
                if (buffer.length == 22) {
                    return keyData + "_ack";
                }
                break;
        }
        return keyData;
    }

    /**
     * 根据类型等获取对应的传感器数据类或者Ack heart类等
     *
     * @param sensorType
     * @param buffer
     * @return
     */
    private BaseSensorData getBaseSensorData(int sensorType, byte[] buffer) {
        switch (sensorType) {

            case 32: //0x20  20Mpa 无线压力传感器
            case 33: //0x21  60MPA
            case 35: //0x23  -0.1~ 1 MPa
            case 36: //0x24  -0.1~1.5
            case 37: //0x25   -0.2 ~ 10
            case 38: //0x26   -1.5 ~ 0 kPa
            case 39: //0x27   0 ~ 2000 hPa  / 10
                if (buffer.length == 22) {
                    return new YaLiAckBean();
                } else {
                    return new YaLiBean();
                }
            case 34: //0x22 -8Kpa差压协议
            case 48: //-2 ~ 2 kPa 差压
                if (buffer.length == 22) {
                    return new ChaYaAckBean();
                } else {
                    return new ChaYaBean();
                }
            case -95: // 激光测距
            case 161: // 激光测距
                if (buffer.length != 16) {
                    switch (buffer.length) {
                        case 25: //防坠器上面的旧协议
                            return new JiGuangBean25();
                        case 26: //新协议
                            return new JiGuangBean26();
                    }
                }
                break;
            default:
                return null;
        }
        return null;
    }

    public void setContentTitle(String contentTitle) {
        this.contentTitle = contentTitle;
    }

    public void setContentText(String contentText) {
        this.contentText = contentText;
    }

    public void setIsDefault(boolean isDeFault) {
        this.isDeFault = isDeFault;
    }

    /**
     * 通过此接口在无法修改此库的情况下，添加新的传感器解析回调；
     */
    public interface OnAddNewSensorType {
        void onGetData(byte[] dataArray, int sensorType);
    }

    /**
     * 通过此接口，自己解析原始串口数据
     */
    public interface OnGetSerialPortDataThread {
        void onGetData(byte[] dataArray, int sensorType);
    }


    @Override
    public void onDestroy() {
        isReadSerial = false;
        ComControl.closeComPort(com);
        stopForeground(true);// 停止前台服务--参数：表示是否移除之前的通知
        notificationManager.cancel(110);
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
